﻿using System;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace dropbox_screen_shooter
{
    class KeyHook
    {
        #region DllImport

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr GetForegroundWindow();

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr SetWindowsHookEx(int idHook,
            LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool UnhookWindowsHookEx(IntPtr hhk);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern int CallNextHookEx(IntPtr hhk, int nCode,
            IntPtr wParam, IntPtr lParam);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr GetModuleHandle(string lpModuleName);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool GetWindowRect(HandleRef hWnd, out Rect lpRect);

        [DllImport("dwmapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr DwmGetWindowAttribute(IntPtr hwnd, int dwAttribute, out Rect pvAttribute, int cbAttribute);

        [DllImport("dwmapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr DwmIsCompositionEnabled(out bool pfEnabled);

        [StructLayout(LayoutKind.Sequential)]
        private struct Rect
        {
            public int Left;
            public int Top;
            public int Right;
            public int Bottom;
        }

        #endregion

        public delegate int LowLevelKeyboardProc(
            int nCode, IntPtr wParam, IntPtr lParam);

        private const int WH_KEYBOARD_LL = 13;
        private const int WM_KEYDOWN = 0x0100;
        private const int WM_SYSKEYUP = 0x0105;
        private const int DWMWA_EXTENDED_FRAME_BOUNDS = 9;
        private static OperatingSystem OS = Environment.OSVersion;

        public static LowLevelKeyboardProc proc = HookCallback;
        public static IntPtr hookID = IntPtr.Zero;
        
        private static int HookCallback(
           int nCode, IntPtr wParam, IntPtr lParam)
        {
            Rect wind = new Rect();
            Rectangle rect;
            int vkCode = Marshal.ReadInt32(lParam);
            if (nCode >= 0 && (wParam == (IntPtr)WM_KEYDOWN))
            {
               
                if ((Keys)vkCode == Keys.PrintScreen)
                {
                    ScreenShooter.MakeFullScreen();
                    if (Options.Default.Paste)
                        return -1;
                }
            }
            if (nCode >= 0 && (wParam == (IntPtr)WM_SYSKEYUP))
            {
                if ((Keys)vkCode == Keys.PrintScreen)
                {
                    bool isAeroOn;
                    DwmIsCompositionEnabled(out isAeroOn);

                    if ((OS.Platform == PlatformID.Win32NT) && (OS.Version.Major >= 6) && isAeroOn)
                    {
                        DwmGetWindowAttribute(GetForegroundWindow(), DWMWA_EXTENDED_FRAME_BOUNDS, out wind, Marshal.SizeOf(wind));
                    }
                    else
                    {
                        GetWindowRect(new HandleRef(null, GetForegroundWindow()), out wind);
                    }
                    rect = new Rectangle(wind.Left, wind.Top, wind.Right - wind.Left, wind.Bottom - wind.Top);
                    ScreenShooter.MakeWindowCopy(rect);
                    if (Options.Default.Paste)
                        return -1;
                }
            }            
            return CallNextHookEx(hookID, nCode, wParam, lParam);
        }

        public static IntPtr SetHook(LowLevelKeyboardProc proc)
        {
            using (Process curProcess = Process.GetCurrentProcess())
            using (ProcessModule curModule = curProcess.MainModule)
            {
                return SetWindowsHookEx(WH_KEYBOARD_LL, proc,
                    GetModuleHandle(curModule.ModuleName), 0);
            }
        }
    }
}
